﻿using System;
using System.Configuration;
using System.Collections.Generic;
using System.Diagnostics.Eventing.Reader;
using System.Linq;
using System.Management;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace EventReaderService
{
    internal static class EventReader
    {

        private static StringBuilder keywords = new StringBuilder();
        private static StringBuilder eventmsg = new StringBuilder();
        private static String TargetUserSid = "";
        private static String TargetUserName = "";
        private static String TargetUserInt = "";
        private static String TargetIp = "";
        private static String LogonType = "";
        private static Int64? _recordId = 0;
        private static StreamWriter ew = new StreamWriter(ConfigurationManager.AppSettings["ErrorLogPath"].ToString(), true, Encoding.UTF8);
        private static bool win2008 = false;

        internal static void Start()
        {
            // This is a Windows Sockets 2 error code.
            const int WSAETIMEDOUT = 10060;

            Socket serverSocket;
            System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();

            String logName = "Security";
            String queryString = "*[System/TimeCreated[timediff(@SystemTime) <= 12000]]";


            EventLogQuery eventsQuery = new EventLogQuery(logName,
               PathType.LogName, queryString);

            EventLogReader logReader;
            //Console.WriteLine("Starting up the server ...");
            try
            {
                // Query the log
                logReader = new EventLogReader(eventsQuery);
            }
            catch (EventLogNotFoundException e)
            {
                //Console.WriteLine("Failed to query the log!");
                //Console.WriteLine(e);
                return;
            }

            int numberOfEvents = 0;
            Random random = new Random();


            IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
            //IPAddress ipAddress = Dns.GetHostAddresses(Dns.GetHostName())[int.Parse(ConfigurationManager.AppSettings["DnsHostNameIndex"].ToString())];
            if (ConfigurationManager.AppSettings["IpOverride"].ToString() != "1")
            {
                foreach (IPAddress ip in Dns.GetHostAddresses(Dns.GetHostName()))
                {
                    if (ip.AddressFamily != AddressFamily.InterNetworkV6 & !IPAddress.IsLoopback(ip) & ip.ToString().StartsWith("10."))
                    {
                        ipAddress = ip;
                    }
                }
            }
            else
            {
                ipAddress = IPAddress.Parse(ConfigurationManager.AppSettings["IpAddress"].ToString());
            }
            int _port = int.Parse(ConfigurationManager.AppSettings["OpenPort"]);
            //IPAddress ipAddress = Dns.GetHostAddresses(ConfigurationManager.AppSettings["DnsHostName"].ToString())];
            // IPAddress ipAddress = new IPAddress(
            //Console.WriteLine("On IP Address:" + ipAddress.ToString());
            bool stopped = false;

            IPEndPoint ipEndpoint = new IPEndPoint(ipAddress, _port);
            while (true)
            {

                // Create a socket and listen for incoming connections.
                using (Socket listenSocket = new Socket(
                    AddressFamily.InterNetwork, SocketType.Stream,
                    ProtocolType.Tcp))
                {
                    listenSocket.Bind(ipEndpoint);
                    listenSocket.Listen(1);

                    // Accept a connection and create a socket to handle it.
                    serverSocket = listenSocket.Accept();
                    //Console.WriteLine("Server is connected.\n");
                }
                #region eventlogreader path
                try
                {

                    try
                    {
                        string query;
                        if (_recordId != 0)
                        {
                            query = "*[System[(EventRecordID > " + _recordId + ")]]";

                        }
                        else
                        {
                            query = "*[System/TimeCreated[timediff(@SystemTime) <= 12000]]";
                        }
                        // Query the log
                        eventsQuery = new EventLogQuery(logName,
                            PathType.LogName, query);
                        logReader = new EventLogReader(eventsQuery);

                    }
                    catch (EventLogNotFoundException e)
                    {
                        //Console.WriteLine("Failed to query the log!");
                        //Console.WriteLine(e);
                        return;
                    }
                    // Send data to the client.
                    //Console.Write("Sending data ... ");
                    // For each event returned from the query
                    for (EventRecord eventInstance = logReader.ReadEvent();
                            eventInstance != null;
                            eventInstance = logReader.ReadEvent())
                    {
                        try
                        {
                            foreach (var key in eventInstance.KeywordsDisplayNames)
                            {
                                keywords.Append(key.ToString());
                                keywords.Append(" ");
                            }
                            List<EventProperty> props = (List<EventProperty>)eventInstance.Properties;
                            // log events with a securityID
                            if (props.Count > 1)
                            {
                                if (props[0].Value.ToString().StartsWith("S-"))
                                {

                                    if (props[4].Value.ToString().StartsWith("S-"))
                                    {
                                        TargetUserSid = props[4].Value.ToString();
                                        TargetUserInt = TargetUserSid.Split('-')[TargetUserSid.Split('-').GetUpperBound(0)];
                                        TargetUserName = props[5].Value.ToString();
                                        LogonType = props[8].Value.ToString();
                                        TargetIp = props[props.Count - 2].Value.ToString();
                                    }
                                    else
                                    {
                                        TargetUserSid = props[0].Value.ToString();
                                        TargetUserInt = TargetUserSid.Split('-')[TargetUserSid.Split('-').GetUpperBound(0)];
                                        TargetUserName = props[1].Value.ToString();
                                        LogonType = props[4].Value.ToString();
                                        TargetIp = props[props.Count - 2].Value.ToString();
                                    }
                                }
                                //log events that do not start with a security ID
                                else
                                {
                                    TargetUserInt = "999999";
                                    TargetUserName = props[0].Value.ToString();
                                    TargetIp = props[props.Count - 1].Value.ToString();
                                }
                            } if (props.Count > 1)
                            {
                                if (props[0].Value.ToString().StartsWith("S-"))
                                {

                                    if (props[4].Value.ToString().StartsWith("S-"))
                                    {
                                        TargetUserSid = props[4].Value.ToString();
                                        TargetUserInt = TargetUserSid.Split('-')[TargetUserSid.Split('-').GetUpperBound(0)];
                                        TargetUserName = props[5].Value.ToString();
                                        LogonType = props[8].Value.ToString();
                                        TargetIp = props[props.Count - 2].Value.ToString();
                                    }
                                    else
                                    {
                                        TargetUserSid = props[0].Value.ToString();
                                        TargetUserInt = TargetUserSid.Split('-')[TargetUserSid.Split('-').GetUpperBound(0)];
                                        TargetUserName = props[1].Value.ToString();
                                        LogonType = props[4].Value.ToString();
                                        TargetIp = props[props.Count - 2].Value.ToString();
                                    }
                                }
                                //log events that do not start with a security ID
                                else
                                {
                                    TargetUserInt = "999999";
                                    TargetUserName = props[0].Value.ToString();
                                    TargetIp = props[props.Count - 1].Value.ToString();
                                }
                            }
                            //if (props.Exists(p => p.Value.ToString().StartsWith("S-") & p.Value.ToString().Length > 10))
                            //{

                            //    TargetUserSid = props.Find(p => p.Value.ToString().StartsWith("S-") & p.Value.ToString().Length > 10).Value.ToString();
                            //    TargetUserInt = TargetUserSid.Split('-')[TargetUserSid.Split('-').GetUpperBound(0)];
                            //    TargetUserName = props[props.FindIndex(p => p.Value.ToString().StartsWith("S-") & p.Value.ToString().Length > 10) + 1].Value.ToString();
                            //}
                            ////may not need the length check
                            //else if (props.Exists(p => p.Value.ToString().StartsWith("S-") & p.Value.ToString().Length < 10))
                            //{
                            //    TargetUserSid = props.Find(p => p.Value.ToString().StartsWith("S-") & p.Value.ToString().Length < 10 & p.Value.ToString().Length > 7).Value.ToString();
                            //    TargetUserInt = TargetUserSid.Split('-')[TargetUserSid.Split('-').GetUpperBound(0)];
                            //    TargetUserName = props[props.FindIndex(p => p.Value.ToString().StartsWith("S-") & p.Value.ToString().Length < 10) + 1].Value.ToString();
                            //}
                            //else
                            //{
                            //    TargetUserInt = "999999";
                            //    TargetUserSid = TargetUserInt;
                            //    TargetUserName = props[0].Value.ToString();
                            //}
                            //if (props.Exists(p => p.Value.ToString().EndsWith("UserName")))
                            //{
                            //    TargetUserName = props.FindLast(p => p.Value.ToString().EndsWith("UserName")).Value.ToString();//.Value.ToString();
                            //}

                            eventmsg.Append(eventInstance.RecordId != null ? eventInstance.RecordId : 1);
                            eventmsg.Append("|");
                            eventmsg.Append(eventInstance.TimeCreated.ToString());
                            eventmsg.Append("|");
                            eventmsg.Append(eventInstance.ProcessId != null ? eventInstance.ProcessId : 0);
                            eventmsg.Append("|");
                            eventmsg.Append(eventInstance.ThreadId != null ? eventInstance.ThreadId : 0);
                            eventmsg.Append("|");
                            eventmsg.Append(eventInstance.Id);
                            eventmsg.Append("|");
                            eventmsg.Append(eventInstance.MachineName);
                            eventmsg.Append("|");
                            eventmsg.Append(TargetUserSid);
                            eventmsg.Append("|");
                            eventmsg.Append(TargetUserInt);
                            eventmsg.Append("|");
                            eventmsg.Append(TargetUserName);
                            eventmsg.Append("|");
                            eventmsg.Append(TargetIp);
                            eventmsg.Append("|");
                            eventmsg.Append(LogonType);
                            eventmsg.Append("|");
                            eventmsg.Append(keywords);
                            eventmsg.Append("\n");

                            int bytesSent = serverSocket.Send(encoding.GetBytes(eventmsg.ToString()), 0, eventmsg.Length, SocketFlags.None);
                            //Console.WriteLine(eventInstance.RecordId + " TargetUserInt " + TargetUserInt + " TargetUserSid " + TargetUserSid + " TargetUserName " + TargetUserName);
                            keywords.Remove(0, keywords.Length);
                            eventmsg.Remove(0, eventmsg.Length);
                            TargetUserSid = "";
                            TargetUserName = "";
                            TargetUserInt = "";
                            TargetIp = "";
                            LogonType = "";
                            _recordId = eventInstance.RecordId;
                            //Console.WriteLine("{0} bytes sent.\n",
                            //    bytesSent.ToString());
                        }
                        catch (Exception e)
                        {
                            keywords.Remove(0, keywords.Length);
                            eventmsg.Remove(0, eventmsg.Length);
                            TargetUserSid = "";
                            TargetUserName = "";
                            TargetUserInt = "";
                            ////Console.WriteLine("Couldn't render event!");
                            ////Console.WriteLine("Exception: Event {0} may not have an XML representation \n\n", ++numberOfEvents);
                            //Console.WriteLine(TargetUserInt + "\n\r" + e);
                        }



                    }


                }
                finally
                {
                    serverSocket.Shutdown(SocketShutdown.Both);
                    //Console.WriteLine("Connection shut down.");
                    serverSocket.Close();
                    logReader = null;
                    System.Threading.Thread.Sleep(8000);
                }
                #endregion
                if (win2008 == false)
                {
                    string Query = String.Format("Select User,TimeGenerated from Win32_NTLogEvent Where Logfile = 'Security'");

                    ManagementObjectSearcher mos = new ManagementObjectSearcher(Query);
                    object o;
                    foreach (ManagementObject mo in mos.Get())
                    {
                        foreach (PropertyData pd in mo.Properties)
                        {
                            o = mo[pd.Name];
                            if (o != null)
                            {
                                Console.WriteLine(pd.Name + " " + pd.Value);
                            }
                        }
                    }
                }// while close

            }
        }

        internal static void Stop()
        {
            keywords = null;
            eventmsg = null;
            TargetUserSid = null;
            TargetUserName = null;
            TargetUserInt = null;

        }
    }
}
